#ifndef __ELF_H_
#define __ELF_H_

#include "types.h"
#include "page.h"

/* Type for a 16-bit quantity.  */
typedef uint16_t Elf64_Half;
/* Types for signed and unsigned 32-bit quantities.  */
typedef uint32_t Elf64_Word;
typedef	int32_t  Elf64_Sword;
/* Types for signed and unsigned 64-bit quantities.  */
typedef uint64_t Elf64_Xword;
typedef	int64_t  Elf64_Sxword;
/* Type of addresses.  */
typedef uint64_t Elf64_Addr;
/* Type of file offsets.  */
typedef uint64_t Elf64_Off;
/* Type for section indices, which are 16-bit quantities.  */
typedef uint16_t Elf64_Section;
/* Type for version symbol information.  */
typedef Elf64_Half Elf64_Versym;

#define EI_NIDENT (16)

// ELF header
typedef struct
{
  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
  Elf64_Half	e_type;			/* Object file type */
  Elf64_Half	e_machine;		/* Architecture */
  Elf64_Word	e_version;		/* Object file version */
  Elf64_Addr	e_entry;		/* Entry point virtual address */
  Elf64_Off	e_phoff;		/* Program header table file offset */
  Elf64_Off	e_shoff;		/* Section header table file offset */
  Elf64_Word	e_flags;		/* Processor-specific flags */
  Elf64_Half	e_ehsize;		/* ELF header size in bytes */
  Elf64_Half	e_phentsize;		/* Program header table entry size */
  Elf64_Half	e_phnum;		/* Program header table entry count */
  Elf64_Half	e_shentsize;		/* Section header table entry size */
  Elf64_Half	e_shnum;		/* Section header table entry count */
  Elf64_Half	e_shstrndx;		/* Section header string table index */
} Elf64_Ehdr;

// Program segment header
typedef struct
{
  Elf64_Word	p_type;			/* Segment type */
  Elf64_Word	p_flags;		/* Segment flags */
  Elf64_Off	p_offset;		/* Segment file offset */
  Elf64_Addr	p_vaddr;		/* Segment virtual address */
  Elf64_Addr	p_paddr;		/* Segment physical address */
  Elf64_Xword	p_filesz;		/* Segment size in file */
  Elf64_Xword	p_memsz;		/* Segment size in memory */
  Elf64_Xword	p_align;		/* Segment alignment */
} Elf64_Phdr;

// Magic number macro
#define EI_MAG0		0		/* File identification byte 0 index */
#define ELFMAG0		0x7f		/* Magic number byte 0 */
#define EI_MAG1		1		/* File identification byte 1 index */
#define ELFMAG1		'E'		/* Magic number byte 1 */
#define EI_MAG2		2		/* File identification byte 2 index */
#define ELFMAG2		'L'		/* Magic number byte 2 */
#define EI_MAG3		3		/* File identification byte 3 index */
#define ELFMAG3		'F'		/* Magic number byte 3 */
#define EI_CLASS	4		/* File class byte index */
#define ELFCLASS64	2		/* 64-bit objects */
#define EI_DATA		5		/* Data encoding byte index */
#define ELFDATA2LSB	1		/* 2's complement, little endian */
#define EI_VERSION	6		/* File version byte index */
#define EV_CURRENT	1		/* Current version */
#define EI_OSABI	7		/* OS ABI identification */
#define ELFOSABI_SYSV		0	/* UNIX System V ABI */
#define EI_ABIVERSION	8		/* ABI version */

#define ET_EXEC		2		/* Executable file */

#define EM_RISCV	243	/* RISC-V */

#define PT_LOAD		1		/* Loadable program segment */

/* Legal values for p_flags (segment flags).  */
#define PF_X		(1 << 0)	/* Segment is executable */
#define PF_W		(1 << 1)	/* Segment is writable */
#define PF_R		(1 << 2)	/* Segment is readable */

uint64 load_elf(Elf64_Ehdr *elf_header, struct pgtable_l3 *table_ptr3, struct vma **vma_dptr);

#endif
